package auctionhaus

import org.springframework.dao.DataIntegrityViolationException
import grails.plugins.springsecurity.Secured
import grails.util.Environment;

class CustomerController {

	static allowedMethods = [save: "POST", update: "POST", delete: "POST"]

	/**
	 * SRV-4: Refactor your Controllers from the previous assignments to use the service methods created in this section (unit test)
	 */
	def crudService;

	@Secured(['ROLE_ADMIN'])
	def index() {
		redirect(action: "list", params: params)
	}

	/**
	 * S-4: Only a user with an admin role is able to view / edit customer screens created in requirements C-1 through C-4 in assignment 2
	 */
	@Secured(['ROLE_ADMIN'])
	def list() {
		params.max = Math.min(params.max ? params.int('max') : 5, 100)
		[customerInstanceList: Customer.list(params), customerInstanceTotal: Customer.count()]
	}

	def create() {
		[customerInstance: new Customer(params)]
	}

	def save() {
		def customerInstance = new Customer(params)

		if(customerInstance.password!=null && ( customerInstance.password.size() <6 || customerInstance.password.size() >8 )) {

			flash.message = message(code: 'customer.password.size.toosmall', args: [
				message(code: 'customer.label', default: 'Customer'),
				params.id
			])


			render(view: "create", model: [customerInstance: customerInstance])
			return
		}

		if (!crudService.createCustomer(customerInstance)) {
			render(view: "create", model: [customerInstance: customerInstance])
			return
		}
		if(!Environment.getCurrent().equals(Environment.TEST)){
			def userRole = Role.findByAuthority('ROLE_USER') ?: crudService.createRole(new Role(authority: 'ROLE_USER'))


			if (!customerInstance.authorities.contains(userRole)) {
				UserRole.create customerInstance, userRole
			}
		}

		flash.message = message(code: 'customer.created.message', args: [
			message(code: 'customer.label', default: 'Customer'),
			customerInstance.username
		])
		redirect(controller:"listing", action: "list", id: customerInstance.id)
	}


	@Secured(['ROLE_USER', 'ROLE_ADMIN'])
	def show() {
		def customerInstance = Customer.get(params.id)
		int paramId = 0

		if(customerInstance)
			paramId = customerInstance.id

		def roleNames;
		
		if(!Environment.getCurrentEnvironment().equals(Environment.TEST))
			roleNames = principal.authorities*.authority

		if(roleNames?.contains('ROLE_ADMIN')||Environment.getCurrent().equals(Environment.TEST)||getAuthenticatedUser().id == paramId ){
			if (!customerInstance) {
				flash.message = message(code: 'default.not.found.message', args: [
					message(code: 'customer.label', default: 'Customer'),
					params.id
				])
				redirect(action: "list")
				return
			}

			[customerInstance: customerInstance]
		}else{
			redirect(controller: "login", action:"denied")
		}
	}

	/**
	 * S-4: Only a user with an admin role is able to view / edit customer screens created in requirements C-1 through C-4 in assignment 2
	 */
	@Secured(['ROLE_ADMIN'])
	def edit() {
		def customerInstance = Customer.get(params.id)
		int paramId = 0

		if(customerInstance)
			paramId = customerInstance.id

		if(Environment.getCurrent().equals(Environment.TEST)||getAuthenticatedUser().id == paramId ){
			if (!customerInstance) {
				flash.message = message(code: 'default.not.found.message', args: [
					message(code: 'customer.label', default: 'Customer'),
					params.id
				])
				redirect(action: "list")
				return
			}

			[customerInstance: customerInstance]
		}else{
			redirect(controller: "login", action:"denied")
		}
	}

	@Secured(['ROLE_ADMIN', 'ROLE_USER'])
	def update() {
		def customerInstance = Customer.get(params.id)
		int paramId = 0

		if(customerInstance)
			paramId = customerInstance.id

		if(Environment.getCurrent().equals(Environment.TEST)||getAuthenticatedUser().id == paramId ){
			if (!customerInstance) {
				flash.message = message(code: 'default.not.found.message', args: [
					message(code: 'customer.label', default: 'Customer'),
					params.id
				])
				redirect(action: "list")
				return
			}

			if (params.version) {
				def version = params.version.toLong()
				if (customerInstance.version > version) {
					customerInstance.errors.rejectValue("version", "default.optimistic.locking.failure",
							[
								message(code: 'customer.label', default: 'Customer')]
							as Object[],
							"Another user has updated this Customer while you were editing")
					render(view: "edit", model: [customerInstance: customerInstance])
					return
				}
			}

			customerInstance.properties = params

			if (!crudService.updateCustomer(customerInstance)) {
				render(view: "edit", model: [customerInstance: customerInstance])
				return
			}

			flash.message = message(code: 'default.updated.message', args: [
				message(code: 'customer.label', default: 'Customer'),
				customerInstance.id
			])
			redirect(action: "show", id: customerInstance.id)
		}else{
			redirect(controller: "login", action:"denied")
		}
	}

	/**
	 * S-4: Only a user with an admin role is able to view / edit customer screens created in requirements C-1 through C-4 in assignment 2
	 */
	@Secured(['ROLE_ADMIN'])
	def delete() {
		def customerInstance = Customer.get(params.id)
		if (!customerInstance) {
			flash.message = message(code: 'default.not.found.message', args: [
				message(code: 'customer.label', default: 'Customer'),
				params.id
			])
			redirect(action: "list")
			return
		}

		int bidSize = getCustomerBidSize(customerInstance)
		int listingSize = getCustomerListingSize(customerInstance)

		//C-4: An existing customer can only be deleted through the web interface if they have 0 listings and 0 bids. The system will present an error message to the user if the delete cannot be performed (unit test of the controller action that has this logic)
		if( bidSize > 0 || listingSize > 0 ) {
			if( bidSize > 0 ) {
				flash.message = message(code: 'customer.bids.delete.constraint', args: [
					message(code: 'customer.label', default: 'Customer'),
					params.id
				])
			}
			if( listingSize > 0) {
				flash.message = message(code: 'customer.listings.delete.constraint', args: [
					message(code: 'customer.label', default: 'Customer'),
					params.id
				])
			}
			redirect(action: "show", id: params.id)
			return
		}
		try {
			if(!Environment.getCurrentEnvironment().equals(Environment.TEST)){
				UserRole.removeAll(customerInstance);
			}
			crudService.deleteCustomer(customerInstance)
			flash.message = message(code: 'default.deleted.message', args: [
				message(code: 'customer.label', default: 'Customer'),
				params.id
			])
			redirect(action: "list")
		}
		catch (DataIntegrityViolationException e) {
			flash.message = message(code: 'default.not.deleted.message', args: [
				message(code: 'customer.label', default: 'Customer'),
				params.id
			])
			redirect(action: "show", id: params.id)
		}
	}

	/* Utility methods */

	def int getCustomerBidSize(Customer customerInstance)
	{
		int bidSize
		if(customerInstance==null || (customerInstance!=null && customerInstance.bids==null)){
			bidSize = 0;
		}
		else{
			bidSize = customerInstance.bids.size()
		}
		return bidSize
	}

	def int getCustomerListingSize(Customer customerInstance)
	{
		int listingSize
		if(customerInstance==null || (customerInstance!=null && customerInstance.listings==null)){
			listingSize = 0;
		}
		else{
			listingSize = customerInstance.listings.size()
		}
		return listingSize
	}
}
